package cfdt.ldl.web.util;


import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cfdt.common.enums.CommonCodeEnum;
import cfdt.common.utils.HMacUtil;
import cfdt.common.exception.CodeException;
import cfdt.tools.json.JsonUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.AntPathMatcher;

import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * <pre>
 * Modify Information:
 * Author       Date          Description
 * ============ ============= ============================
 * liyuejiang      2021年1月20日     用于sign串比较
 * </pre>
 */

public final class SignUtil {

    private static final Logger logger = LoggerFactory.getLogger("SignUtil");

    private SignUtil() {
    }

    public static Boolean compareSign(String originSign, String jsonStr, String secretKey) throws CodeException {

        if (StrUtil.isEmpty(originSign)) {
            //原有的签名串为空，直接返回false
            return false;
        }
        String localSign = getSignStr(jsonStr, secretKey);
        logger.debug("localSign:{}", localSign);
        return StrUtil.equalsIgnoreCase(localSign, originSign);
    }

    /**
     * 后端获取签名串
     *
     * @param jsonStr requestBody
     * @param secretKey   secretKey
     * @return 后端生成的签名串，用来和前端传的进行比较
     * @throws CodeException
     */
    private static String getSignStr(String jsonStr, String secretKey) throws CodeException {

        if (StrUtil.isEmpty(jsonStr)) {
            throw new CodeException(CommonCodeEnum.CODE_1002, "jsonStr");
        }
        String compareDataStr = getCompareDataStr(jsonStr);
        // 国密签名
        return HMacUtil.sm3Hex(secretKey, compareDataStr);
    }

    /**
     * 将数据按照规则生成。将json 传转换
     * 按照key排序，然后用&拼接，转换成大写
     *
     * @param jsonStr requestBody
     * @return
     */
    private static String getCompareDataStr(String jsonStr) {

        if (StrUtil.isEmpty(jsonStr)) {
            return jsonStr;
        }

        TreeMap<String, String> map = JsonUtil.toBean(jsonStr, TreeMap.class, true);

        StringBuilder sign = new StringBuilder();
        for (Map.Entry entry : map.entrySet()) {
            if(entry.getValue()!=null){
                JsonUtil.getSortReqDataStr(sign,entry);
            }
        }
        // 最终签名串
        String signResult = sign.toString();

        return signResult.endsWith("&") ?
                signResult.substring(0, signResult.length() - 1) :
                signResult;
    }

    /**
     * sql注入校验
     * @param jsonStr
     * @param illegalCharRegex
     * @param illegalSQL
     * @return
     * @throws CodeException
     */
    public static boolean check(String jsonStr,String illegalCharRegex,String illegalSQL) throws CodeException {
        boolean flag = false;
        flag = illegalStrCheck(jsonStr,illegalCharRegex);
        if (flag) {
            flag = sqlCheck(jsonStr,illegalSQL);
            logger.info( "sql非法校验结果：" + flag + (flag ? "-通过" : "-不通过"));
        }
        if (!flag) {
            logger.error( CommonCodeEnum.CODE_3002.getDesc());
            throw new CodeException(CommonCodeEnum.CODE_3002);
        }
        return true;
    }

    /**
     * 校验非法字符
     *
     * @param sourceStr
     * @return
     */
    private static boolean illegalStrCheck(String sourceStr , String illegalCharRegex) {
        if (StrUtil.isEmpty(illegalCharRegex)) {
            return true;
        }
        if (StrUtil.isNotEmpty(sourceStr)) {
            Pattern pattern = Pattern.compile(illegalCharRegex);
            Matcher matcher = pattern.matcher(sourceStr);
            return !matcher.find();
        } else {
            return true;
        }
    }

    /**
     * sql非法校验
     *
     * @param sourceStr
     * @return
     */
    private static boolean sqlCheck(String sourceStr,String illegalSQL) {
        if (StrUtil.isEmpty(illegalSQL)) {
            return true;
        }
        if (sourceStr == null) {
            return true;
        }
        String sourceStrLower = sourceStr.toLowerCase();

        Pattern pattern = Pattern.compile(illegalSQL);
        Matcher matcher = pattern.matcher(sourceStrLower);

        return !matcher.find();
    }

    /**
     * 判断指定url地址是否匹配指定url集合中的任意一个
     *
     * @param urlPath 指定url地址
     * @param urls    需要检查的url集合
     * @return 是否匹配  匹配返回true，不匹配返回false
     */
    public static boolean matches(String urlPath, List<String> urls) {
        if (StrUtil.isEmpty(urlPath) || CollUtil.isEmpty(urls)) {
            return false;
        }
        for (String url : urls) {
            if (isMatch(url, urlPath)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 判断url是否与规则配置:
     * ? 表示单个字符
     * * 表示一层路径内的任意字符串，不可跨层级
     * ** 表示任意层路径
     *
     * @param url     匹配规则
     * @param urlPath 需要匹配的url
     * @return
     */
    public static boolean isMatch(String url, String urlPath) {
        AntPathMatcher matcher = new AntPathMatcher();
        return matcher.match(url, urlPath);
    }

    public static void main(String[] args) throws CodeException {
        String jsonStr =
                "        {\n" +
                "            \"name\": \"chen\"\n" +
                "        }";

//        String jsonStr =
//                "{\n" +
//                        "    \"userName\":\"chenzhibin\",\n" +
//                        "    \"password\":\"123456\"\n" +
//                        "}";

        String secretKey = "Cpcn1234#";
        secretKey = "eyJhbGdOYW1lIjoiU00zIn0=.eyJjbGFpbXNNYXAiOnsidXNlcklkIjoiMSJ9fQ==.8kdNf6K+or5CoJLPqUTxUKK9UJF5KOe359L5VizcuCw=";
        System.out.println(getSignStr(jsonStr, secretKey));
    }
}
